package cbs.jdtag.io;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import cbs.jdtag.AppContext;
import cbs.jdtag.DataModel2;
import cbs.jdtag.DataModel2.Alignment;
import cbs.jdtag.DataModel2.Token;
import cbs.jdtag.DataModel2.TokenFile;

public class XMLWriter {
	private static final Logger LOGGER = Logger.getLogger(XMLWriter.class.getName());
	private static final DocumentBuilderFactory DOMFACTORY = DocumentBuilderFactory.newInstance();
	private static DocumentBuilder builder;
	
	static {
		try {
			builder = DOMFACTORY.newDocumentBuilder();
		}
		catch (ParserConfigurationException e) {
			throw new RuntimeException(e);
		}
	}
	
	private XMLWriter() { }
	
	public static void save(File f) throws TransformerFactoryConfigurationError, TransformerException, DOMException, URISyntaxException {
		DataModel2 dm = AppContext.getDM();
		
		Document doc = builder.newDocument();
		Element root = doc.createElement("DTAGalign");
		doc.appendChild(root);
		
		URI baseDir = null;
		if (dm.getAlignmentFile().getParentFile() != null) {
			baseDir = dm.getAlignmentFile().getParentFile().toURI();
		}
		else {
			baseDir = new File(AppContext.getRecentlyUsedDir() + "/" + dm.getAlignmentFile()).getParentFile().toURI();
		}
		TokenFile tf;
		
		Element srcFile = doc.createElement("alignFile");
		root.appendChild(srcFile);
		srcFile.setAttribute("key", dm.getKey(0));
		tf = dm.tokenFiles.get(dm.getKey(0));
		srcFile.setAttribute("href", baseDir.relativize(tf.href.toURI()).toString());	
		srcFile.setAttribute("sign", dm.tokenFiles.get(dm.getKey(0)).sign);
		
		Element tgtFile = doc.createElement("alignFile");
		root.appendChild(tgtFile);
		tgtFile.setAttribute("key", dm.getKey(1));
		tf = dm.tokenFiles.get(dm.getKey(1));
		tgtFile.setAttribute("href", baseDir.relativize(tf.href.toURI()).toString());	
		tgtFile.setAttribute("sign", dm.tokenFiles.get(dm.getKey(1)).sign);
		
		Iterator<Alignment> it = dm.getAlignmentIterator();
		while (it.hasNext()) {
			Alignment a = it.next();
			if (a.getSrcTokens() == null || a.getSrcTokens().isEmpty()
					|| a.getTgtTokens() == null || a.getTgtTokens().isEmpty()) {
				LOGGER.warning("Skipping empty alignment.");
				continue;
			}
			
			Element e = doc.createElement("align");
			root.appendChild(e);
			
			StringBuffer out = new StringBuffer();
			StringBuffer outsign = new StringBuffer();
			Iterator<Token> srcTokenIt = a.getSrcTokens().iterator();
			while (srcTokenIt.hasNext()) {
				Token t = srcTokenIt.next();
				out.append(t.key + t.id);
				outsign.append(t.text);
				outsign.append(" ");
			}
			
			StringBuffer in = new StringBuffer();
			StringBuffer insign = new StringBuffer();
			Iterator<Token> tgtTokenIt = a.getTgtTokens().iterator();
			while (tgtTokenIt.hasNext()) {
				Token t = tgtTokenIt.next();
				in.append(t.key + t.id);
				insign.append(t.text);
				insign.append(" ");
			}
			
			e.setAttribute("out", out.toString());
			e.setAttribute("type", a.getType());
			e.setAttribute("in", in.toString());
			e.setAttribute("creator", a.getCreator());
			e.setAttribute("insign", insign.substring(0, insign.length() - 1));
			e.setAttribute("outsign", outsign.substring(0, outsign.length() - 1));
		}
		
		Source source = new DOMSource(doc);
        Result result = new StreamResult(f);

        // Write the DOM document to the file
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(source, result);
	}
}
